#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h> // socket的函数原型是int socket(int domain（协议簇）, int type（套接字的类型）, int protocol（某个特定协议);
#include <netinet/in.h>
#include <netinet/ether.h>
#include <net/ethernet.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/if_packet.h>
#include <time.h>

// 以太网帧头部结构
struct ethheader {
    unsigned char  dst_mac[6];// 目标MAC地址
    unsigned char  src_mac[6];// 源MAC地址
    unsigned short eth_type;// 帧中数据协议类型代码
};

// 协议类型统计
struct protocol_stats {
    unsigned int total;
    unsigned int ip;
    unsigned int arp;
    unsigned int ipv6;
    unsigned int other;
};

// 将MAC地址转换为可读字符串
void mac_to_string(const unsigned char *mac, char *buf)
{
    sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}

// 打印统计信息
void print_stats(const struct protocol_stats *stats)
{
    printf("\n=== 统计信息 ===\n");
    printf("总帧数: %u\n", stats->total);
    printf("IPv4: %u (%.2f%%)\n", stats->ip, (float)stats->ip / stats->total * 100);
    printf("ARP: %u (%.2f%%)\n", stats->arp, (float)stats->arp / stats->total * 100);
    printf("IPv6: %u (%.2f%%)\n", stats->ipv6, (float)stats->ipv6 / stats->total * 100);
    printf("其他协议: %u (%.2f%%)\n", stats->other, (float)stats->other / stats->total * 100);
}

int main(int argc, char *argv[])
{
    int raw_socket;
    struct sockaddr saddr;
    int saddr_len = sizeof(saddr);
    unsigned char *buffer = (unsigned char *)malloc(65536);
    struct protocol_stats stats = {0, 0, 0, 0, 0};
    int count = 0;
    int max_packets = -1; // 默认无限捕获
    
    // 解析命令行参数
    if (argc == 2) max_packets = atoi(argv[1]);
    
    // 创建原始套接字
    raw_socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (raw_socket == -1)
	{
        perror("socket");
        exit(EXIT_FAILURE);
    }
    
    printf("开始捕获网络数据包...\n");
    printf("按Ctrl+C停止捕获并显示统计信息\n\n");
    
    // 捕获数据包
    while (1)
	{
        if (max_packets > 0 && count >= max_packets) break;
        
        int data_size = recvfrom(raw_socket, buffer, 65536, 0, &saddr, (socklen_t *)&saddr_len);
        if (data_size < 0)
		{
            perror("recvfrom");
            close(raw_socket);
            free(buffer);
            exit(EXIT_FAILURE);
        }
        
        // 解析以太网头部
        struct ethheader *eth = (struct ethheader *)buffer;
        
        // 转换MAC地址为可读格式
        char src_mac[18], dst_mac[18];
        mac_to_string(eth->src_mac, src_mac);
        mac_to_string(eth->dst_mac, dst_mac);
        
        // 获取协议类型
        unsigned short protocol = ntohs(eth->eth_type);
        char *protocol_str;
        
        // 更新统计信息
        stats.total++;
        switch (protocol)
		{
            case ETH_P_IP:
                protocol_str = "IPv4";
                stats.ip++;
                break;
            case ETH_P_ARP:
                protocol_str = "ARP";
                stats.arp++;
                break;
            case ETH_P_IPV6:
                protocol_str = "IPv6";
                stats.ipv6++;
                break;
            default:
                protocol_str = "其他";
                stats.other++;
                break;
        }
        
        // 打印捕获的信息
        printf("数据包 #%d\n", ++count);
        printf("源MAC: %s\n", src_mac);
        printf("目的MAC: %s\n", dst_mac);
        printf("协议类型: 0x%04x (%s)\n", protocol, protocol_str);
        printf("数据包大小: %d 字节\n\n", data_size);
    }
    
    // 打印统计信息
    print_stats(&stats);
    
    // 清理资源
    close(raw_socket);
    free(buffer);
    
    return 0;
}